package app

import (
	"fmt"
	"net/http"
)

// @title err
// @description 非业务错误代码

var (
	Success       = NewResError(10000, "请求成功")
	ServerError   = NewResError(10001, "对不起, 服务器错误，请联系客服")
	InvalidParams = NewResError(10002, "对不起, 无效的参数")
	NotFound      = NewResError(10003, "对不起，您请求的服务不存在")

	UnauthorizedAuthNotExist  = NewResError(10004, "对不起, 登陆失败，无效的用户名或密码")
	UnauthorizedTokenError    = NewResError(10005, "对不起, 鉴权失败，无效的Token")
	UnauthorizedTokenTimeout  = NewResError(10006, "对不起, 鉴权失败，Token已失效")
	UnauthorizedTokenGenError = NewResError(10007, "对不起, 鉴权失败，Token生成失败")

	UnauthorizedAuthNotLogin = NewResError(10008, "对不起, 您没有登陆")
	UnauthorizedNotAuth      = NewResError(10009, "对不起, 您没有权限")
	MethodNotAllowed         = NewResError(10010, "对不起, 你没有访问指定Http Method的权限")
	RouteNotAllowed          = NewResError(10011, "对不起, 你没有访问指定Route的权限")

	TooManyRequests = NewResError(10012, "对不起, 请求过于频繁")
)

// http返回错误中间数据结构
type ResError struct {
	code int      `json:"code"`
	msg  string   `json:"msg"`
	data []string `json:"data"`
}

var codes = map[int]string{}

// 构建新错误
// 同一个业务逻辑避免出现相似的code
func NewResError(code int, msg string) *ResError {
	if _, ok := codes[code]; ok {
		panic(fmt.Sprintf("sorry, code %d alreay exist", code))
	}

	codes[code] = msg
	return &ResError{code: code, msg: msg}
}

// 实现错误接口
func (re *ResError) Error() string {
	return fmt.Sprintf("错误码:%d, 错误信息:%s", re.Code(), re.Msg())
}

// get
func (re ResError) Code() int {
	return re.code
}

// get
func (re ResError) Msg() string {
	return re.msg
}

// get
func (re ResError) Data() []string {
	return re.data
}

// 附加额外的输出字符串
func (re *ResError) WithData(data ...string) *ResError {
	re.data = []string{}
	for _, d := range data {
		re.data = append(re.data, d)
	}

	return re
}

// http code转换
func (re *ResError) StatusCode() int {
	switch re.Code() {
	case Success.Code():
		return http.StatusOK
	case ServerError.Code():
		return http.StatusInternalServerError
	case InvalidParams.Code():
		return http.StatusBadRequest
	case NotFound.Code():
		return http.StatusNotFound
	case UnauthorizedAuthNotExist.Code():
		fallthrough
	case UnauthorizedTokenError.Code():
		fallthrough
	case UnauthorizedTokenTimeout.Code():
		fallthrough
	case UnauthorizedAuthNotLogin.Code():
		fallthrough
	case UnauthorizedNotAuth.Code():
		fallthrough
	case UnauthorizedTokenGenError.Code():
		return http.StatusUnauthorized
	case MethodNotAllowed.Code():
		return http.StatusForbidden
	case RouteNotAllowed.Code():
		return http.StatusForbidden
	case TooManyRequests.Code():
		return http.StatusTooManyRequests
	}

	return http.StatusInternalServerError
}
